package models

import (
	"time"

	"github.com/astaxie/beego"
	"github.com/dgrijalva/jwt-go"
)

//token私钥
var mySigningKey = []byte("weilongtang")

//生成jwt token
func GeneralJwtToken(uid int) string {
	// 带权限创建令牌
	claims := make(jwt.MapClaims)
	claims["uid"] = uid
	claims["exp"] = time.Now().Add(time.Hour * 24 * 7).Unix() //2小时有效期，过期需要重新登录获取token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	ss, err := token.SignedString(mySigningKey)
	if err != nil {
		beego.Error("parase with claims failed.", err)
		return ""
	}
	return ss
}

//验证token是否有效
func CheckToken(tokenString string) (success bool, e *ControllerError) {
	var errInputData ControllerError

	beego.Debug("tokenString:", tokenString)

	if tokenString == "" {
		beego.Error("tokenString invalid:", tokenString)
		errInputData.Errcode = ERRCODE_TokenAuth_InvaildString
		errInputData.Errmsg = "token参数不能为空"
		return false, &errInputData
	}

	// Parse token
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return mySigningKey, nil
	})
	if err != nil {
		beego.Error("Parse token:", err)
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				// That‘s not even a token
				errInputData.Errcode = ERRCODE_TokenAuth_IllegalToken
				errInputData.Errmsg = "That‘s not even a token"
				return false, &errInputData
			} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
				// Token is either expired or not active yet
				errInputData.Errcode = ERRCODE_TokenAuth_TokenExpired
				errInputData.Errmsg = "Token is either expired or not active yet"
				return false, &errInputData
			} else {
				// Couldn‘t handle this token
				errInputData.Errcode = ERRCODE_TokenAuth_OtherError
				errInputData.Errmsg = "Couldn‘t handle this token"
				return false, &errInputData
			}
		} else {
			// Couldn‘t handle this token
			errInputData.Errcode = ERRCODE_TokenAuth_OtherError
			errInputData.Errmsg = "Couldn‘t handle this token"
			return false, &errInputData
		}
	}

	if !token.Valid {
		beego.Error("Token invalid:", tokenString)
		errInputData.Errcode = ERRCODE_TokenAuth_InvaildToken
		errInputData.Errmsg = "Couldn‘t handle this token"
		return false, &errInputData
	}

	return true, nil
}

//解析uid
func ParseUidFromToken(tokenString string) (uid int, e *ControllerError) {
	var errInputData ControllerError

	if tokenString == "" {
		beego.Error("parseUidFromToken tokenString is null")

		errInputData.Errcode = ERRCODE_TokenAuth_InvaildString
		errInputData.Errmsg = "tokenString invalid:" + tokenString
		return -1, &errInputData
	}

	// Parse token
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		return mySigningKey, nil
	})

	if err != nil {
		beego.Error("Parse token:", err)
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				// That‘s not even a token
				errInputData.Errcode = ERRCODE_TokenAuth_IllegalToken
				errInputData.Errmsg = "That‘s not even a token"
				return -1, &errInputData
			} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {
				// Token is either expired or not active yet
				errInputData.Errcode = ERRCODE_TokenAuth_TokenExpired
				errInputData.Errmsg = "Token is either expired or not active yet"
				return -1, &errInputData
			} else {
				// Couldn‘t handle this token
				errInputData.Errcode = ERRCODE_TokenAuth_OtherError
				errInputData.Errmsg = "Couldn‘t handle this token"
				return -1, &errInputData
			}
		} else {
			// Couldn‘t handle this token
			errInputData.Errcode = ERRCODE_TokenAuth_OtherError
			errInputData.Errmsg = "Couldn‘t handle this token"
			return -1, &errInputData
		}
	} else {
		if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
			return int(claims["uid"].(float64)), nil
		}
	}

	return -1, nil
}
